#pragma once
#include "qfile.h"


namespace micro
{
namespace  files
{


class QFileMap
{

    QString m_fileName;
    QFile  m_file;

    HANDLE m_hFileMap;
    LPVOID m_pFileMap;

public:

    QFileMap()
    {
        //m_fileName = str;
        m_hFileMap = nullptr;
        m_pFileMap = nullptr;
    }



    ~QFileMap()
    {
        Close();
    }

    bool Open( const QString & str, bool readWrite = false )
    {
        m_fileName = str;
        bool bo = m_file.Open( m_fileName,  ( readWrite ? QFile::modeReadWrite : QFile::modeRead ) | QFile::shareDenyWrite );

        if ( false == bo )
            return false;


        m_hFileMap = ::CreateFileMapping( m_file , nullptr, ( readWrite ? PAGE_READWRITE : PAGE_READONLY ),	0, 0, nullptr );

        if ( nullptr == m_hFileMap )
            return false;


        // Get pointer to memory representing file
        m_pFileMap = ::MapViewOfFile( m_hFileMap, ( readWrite ? FILE_MAP_WRITE : FILE_MAP_READ ), 0, 0, 0 );

        if ( !m_pFileMap )
        {
            throw QError();
        }

        return ( nullptr != m_pFileMap );
    }


    void Close()
    {

        ///FlushViewOfFile
        if ( m_pFileMap )
        {
            ::UnmapViewOfFile( m_pFileMap );
            m_pFileMap = nullptr;
        }

        if ( m_hFileMap )
        {
            CloseHandle( m_hFileMap );
            m_hFileMap = nullptr;
        }

        //maybe not mine
        m_file.Close();
    }


    LPBYTE  GetMemory()
    {
        return reinterpret_cast<LPBYTE>( m_pFileMap );
    }


    LONGLONG GetMemSize()
    {
        return m_file.GetFileSize();
    }

    bool IsOpen()
    {
        return nullptr != m_pFileMap;
    }

    operator bool ()
    {
        return IsOpen();
    }



};

class QMemReader
{
    LPBYTE		m_data;
    ULONGLONG	m_size;
    bool		m_release;

public:
    QMemReader( LPBYTE data, ULONGLONG size, bool release = false )
    {
        m_data = data;
        m_size = size;
        m_release = release;
    }

    ~QMemReader()
    {
        if ( m_release )
            delete [] m_data;
    }

    template <class TX>
    TX & Get( ULONGLONG offset ) // Get object of arbitrary type from buffer
    {
        if ( offset >= m_size )
        {
            throw L"out of range";
            offset = 0;
        }

        return *( TX * )( m_data + offset );
    }
};




}

}//micro